package com.w.usercenter.service.impl;

import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.w.usercenter.common.ErrorCode;
import com.w.usercenter.constants.UserConstants;
import com.w.usercenter.exception.BusinessException;
import com.w.usercenter.mapper.UserMapper;
import com.w.usercenter.mode.domain.User;
import com.w.usercenter.mode.request.UserLoginOrRegisterRequest;
import com.w.usercenter.service.UserService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author w
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2024-08-06 20:43:13
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {
    private static final String SALT = "w";

    @Override
    @Transactional
    public long userRegister(UserLoginOrRegisterRequest request) {
        //校验
        checkParams(request, UserConstants.REGISTER);
        //密码加密
        String encryptPassword = DigestUtils.md5Hex(request.getUserPassword() + SALT);
        //保存
        User user = new User();
        //生成指定长度的字母和数字的随机组合字符串
        user.setUsername(RandomStringUtils.randomAlphanumeric(5));
        user.setUserAccount(request.getUserAccount());
        user.setUserPassword(encryptPassword);
        user.setPlanetCode(request.getPlanetCode());
        boolean result = this.save(user);
        if (!result) {
            return 0L;
        }
        return user.getId();
    }

    @Override
    public User userLogin(UserLoginOrRegisterRequest loginRequest, HttpServletRequest request) {
        //校验参数
        checkParams(loginRequest, UserConstants.LOGIN);
        //账户校验
        User one = lambdaQuery().eq(User::getUserAccount, loginRequest.getUserAccount()).one();
        String encryptPassword = DigestUtils.md5Hex(loginRequest.getUserPassword() + SALT);
        if (ObjectUtils.isEmpty(one) || !encryptPassword.equals(one.getUserPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在/密码错误");
        }
        //用户信息脱敏
        User safetyUser = getSafetyUser(one);
        //添加用户态,将登录成功的用户信息存入session会话中,便于后续访问的调用
        request.getSession().setAttribute(UserConstants.LOGIN_USER_STATE, safetyUser);
        HttpSession session = request.getSession();
        log.info("保存的session id:" + session.getId());
        return safetyUser;
    }

    @Override
    public boolean userLogin(HttpServletRequest request) {
        if (ObjectUtils.isEmpty(request)) {
            return false;
        }
        request.getSession().removeAttribute(UserConstants.LOGIN_USER_STATE);
        return true;
    }

    @Override
    public User current(HttpServletRequest request) {
        HttpSession session = request.getSession();
        log.info("读取的session id:" + session.getId());
        Object object = request.getSession().getAttribute(UserConstants.LOGIN_USER_STATE);
        User user = (User) object;
        if (ObjectUtils.isEmpty(user)) {
            return null;
        }
        Long id = user.getId();
        User byId = this.getById(id);
        return getSafetyUser(byId);
    }

    @Override
    public User getSafetyUser(User originUser) {
        if (ObjectUtils.isEmpty(originUser)) {
            return null;
        }
        originUser.setUserPassword(null);
        return originUser;
    }

    @Override
    public List<User> searchList(User user) {
        if (ObjectUtils.isEmpty(user)) {
            return new ArrayList<>();
        }
        return this.baseMapper.searchList(user);
    }

    @Override
    public User searchOneById(Long id) {
        if (ObjectUtils.isEmpty(id)) {
            return null;
        }
        return this.getById(id);
    }

    @Override
    @Transactional
    public boolean addUser(User user) {
        if (ObjectUtils.isEmpty(user)) {
            return false;
        }
        user.setUserPassword(DigestUtils.md5Hex(user.getUserPassword() + SALT));
        return this.save(user);
    }

    @Override
    @Transactional
    public boolean editUserById(User user) {
        if (ObjectUtils.isEmpty(user)) {
            return false;
        }
        return this.updateById(user);
    }

    @Override
    @Transactional
    public boolean removeUserList(List<Long> ids) {
        if (ObjectUtils.isEmpty(ids)) {
            return false;
        }
        return this.removeBatchByIds(ids);
    }

    private void checkParams(UserLoginOrRegisterRequest request, String type) {
        //登录or注册都有
        if (ObjectUtils.isEmpty(request) || StringUtils.isAnyEmpty(request.getUserAccount(), request.getUserPassword())) {
            throw new BusinessException(ErrorCode.NULL_ERROR);
        }
        if (request.getUserAccount().length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户长度不小于4位");
        }

        boolean matches = Pattern.matches(UserConstants.PASSWORD_REGEX, request.getUserPassword());
        if (!matches) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码必须是由数字和英文组成，且大于等于8个字符");
        }

        // 注册独有
        if (type.equals(UserConstants.REGISTER)) {

            if (StringUtils.isAnyEmpty(request.getCheckPassword(), request.getPlanetCode())) {
                throw new BusinessException(ErrorCode.NULL_ERROR);
            }
            if (!request.getUserPassword().equals(request.getCheckPassword())) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次密码不一致");
            }
            matches = Pattern.matches(UserConstants.PLANETCODE_REGEX, request.getPlanetCode());
            if (!matches) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "星球编码必须是数字加英文,且大于等于4位");
            }
            //账户重复
            long count = lambdaQuery().eq(User::getUserAccount, request.getUserAccount()).count();
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账户已存在");
            }
        }
    }

    /**
     * 根据标签搜素用户 sql方式
     *
     * @param tagNameList 标签列表
     * @return 用户
     */
    @Override
    public List<User> searchUserByTagsOnSql(List<String> tagNameList) {
        if (ObjectUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "标签不能为空");
        }
        LambdaQueryChainWrapper<User> userLambdaQueryChainWrapper = this.lambdaQuery();
        for (String tag : tagNameList) {
            userLambdaQueryChainWrapper.like(User::getTags, tag);
        }
        List<User> list = userLambdaQueryChainWrapper.list();
        return list.stream().map(this::getSafetyUser).collect(Collectors.toList());
    }

    /**
     * 根据标签搜素用户 内存方式
     *
     * @param tagNameList 标签列表
     * @return 用户
     */
    @Override
    public List<User> searchUserByTagsOnCache(List<String> tagNameList) {
        if (ObjectUtils.isEmpty(tagNameList)) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "标签不能为空");
        }
        List<User> list = this.lambdaQuery().list();
        Gson gson = new Gson();
        return list.stream().filter(user -> {
            if (StringUtils.isEmpty(user.getTags())){
                return false;
            }
            Set<String> tempTags = gson.fromJson(user.getTags(), new TypeToken<Set<String>>() {}.getType());

            for (String tag : tagNameList) {
                if (!tempTags.contains(tag)) {
                    return false;
                }
            }
            return true;
        }).map(this::getSafetyUser).collect(Collectors.toList());

    }
}




